/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.ui.rich.full.command;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.ListIterator;

import javax.swing.JInternalFrame;

import br.ufmg.dees.insane.commons.command.Command;
import br.ufmg.dees.insane.commons.controller.Controller;
import br.ufmg.dees.insane.commons.view.DrawingArea;
import br.ufmg.dees.insane.model.geo.GControlPoint;
import br.ufmg.dees.insane.model.geo.GPoint;
import br.ufmg.dees.insane.model.geo.GQuadCurve;
import br.ufmg.dees.insane.ui.rich.full.InsaneInternalInterface;
import br.ufmg.dees.insane.ui.rich.full.controller.GeometricController;

/** The AddQuadMouse command.
 *
 * @author Fonseca, Flavio & Pitangueira, Roque
 * @since February 2004
 */
public class AddQuadMouseCommand implements Command, Cloneable {

	private InsaneInternalInterface parent;
	private Controller controller;
	private DrawingArea da;
	private int clicks = 0;
	private GPoint ini;
	private GPoint ctrl;
	private GPoint fin;
	private GQuadCurve q;
	private ArrayList<GPoint> newCtrlPoints = new ArrayList<GPoint>();
	private ArrayList<GPoint> newPoints = new ArrayList<GPoint>();
	
//*****************************************************************************
	
	/** Constructor method. */
	public AddQuadMouseCommand(JInternalFrame parent) {
		this.parent = (InsaneInternalInterface)parent;
		controller = this.parent.getController();
		da = this.parent.getDrawing();
	}
	
//*****************************************************************************
	
	/** Execute method. */
public void execute() {
		
		Point2D po = da.getWorldPoint();
		AddControlPointCommand cpc = new AddControlPointCommand(parent);
		
		clicks ++;
		
		if (clicks % 3 == 1) {
			if (!controller.contains(po)){
				GPoint p = new GPoint(po);
				controller.add(p);
				da.repaint();
				ini = (GPoint)controller.get(po);
				newPoints.add(ini);
				parent.addOutputText(parent.getResourceBundle().getString("cmIniPointCreated") + " " + ini.getX() + ", " + ini.getY());
			}else{
				ini = (GPoint)controller.get(po);
				parent.addOutputText(parent.getResourceBundle().getString("cmIniPointChosen") + " " + ini.getX() + ", " + ini.getY());
			}
			PreviewLineCommand pl = new PreviewLineCommand(parent);
			pl.setInitialPoint(da.getViewPoint(ini));
			da.setMovedCommand(pl);
			da.setRepainting(true);
			da.repaint();
			parent.addOutputText(parent.getResourceBundle().getString("cmSpecControlPoint"));
			parent.getConsole().setLastPoint(new Point2D.Double(ini.getX(), ini.getY()));
		}else if (clicks % 3 == 2) {
			if (!((GeometricController)controller).containsControl(po)){
				cpc.execute();
				ctrl = (GPoint) controller.get(po);
				parent.addOutputText(parent.getResourceBundle().getString("cmControlPointCreated") + " " + ctrl.getX() + ", " + ctrl.getY());
				newCtrlPoints.add(ctrl);
			}else{
				ctrl = (GPoint)controller.get(po);
				parent.addOutputText(parent.getResourceBundle().getString("cmControlPointChosen") + " " + ctrl.getX() + ", " + ctrl.getY());
			}
			PreviewQuadCommand pq = new PreviewQuadCommand(parent);
			pq.setInitialPoint(da.getViewPoint(ini));
			pq.setCtrlPoint(da.getViewPoint(ctrl));
			da.setMovedCommand(pq);
			da.setRepainting(true);
			da.repaint();
			parent.addOutputText(parent.getResourceBundle().getString("cmSpecifyIniPoint"));
			parent.getConsole().setLastPoint(new Point2D.Double(ctrl.getX(), ctrl.getY()));
		}else{
			if(po.getX()!=ini.getX() || po.getY()!=ini.getY()) {
				if (!controller.contains(po)){
					GPoint p = new GPoint(po);
					controller.add(p);
					da.repaint();
					newPoints.add((GPoint)controller.get(po));
					fin = (GPoint)controller.get(po);
					parent.addOutputText(parent.getResourceBundle().getString("cmFinalPointCreated") + " " + fin.getX() + ", " + fin.getY());
				}else{
					fin = (GPoint)controller.get(po);
					parent.addOutputText(parent.getResourceBundle().getString("cmControlPointChosen") + " " + fin.getX() + ", " + fin.getY());
				}
				da.setMovedCommand(null);
				da.setRepainting(false);
				da.setShape(null);
				q = new GQuadCurve(ini, ctrl, fin);
				controller.add(q);
				da.repaint();
				parent.getConsole().setLastPoint(new Point2D.Double(fin.getX(), fin.getY()));
				parent.addOutputText(parent.getResourceBundle().getString("cmSpecifyIniPoint"));
				parent.addToUndo((Command)this.clone());
				newCtrlPoints.clear();
				newPoints.clear();
			} else {
				parent.addOutputText(parent.getResourceBundle().getString("cmMustBeDifferent"));
				parent.addOutputText(parent.getResourceBundle().getString("cmSpecFinalPoint"));
				clicks--;
			}
		}
	}
	
//*****************************************************************************
	
	/** Undo method.*/
	public void undo() {
		controller.remove(q);
		ListIterator newCP = newCtrlPoints.listIterator();
		while (newCP.hasNext()) {
			GControlPoint ncp = (GControlPoint) newCP.next();
			controller.remove(ncp);
		}
		ListIterator newP = newPoints.listIterator();
		while (newP.hasNext()) {
			GPoint np = (GPoint) newP.next();
			controller.remove(np);
		}
	}
	
//*****************************************************************************
	
	/** Redo method.*/
	public void redo() {
		ListIterator newP = newPoints.listIterator();
		while (newP.hasNext()) {
			GPoint np = (GPoint) newP.next();
			controller.add(np);
		}
		ListIterator newCP = newCtrlPoints.listIterator();
		while (newCP.hasNext()) {
			GControlPoint ncp = (GControlPoint) newCP.next();
			controller.add(ncp);
		}
		controller.add(q);
	}
	
//*****************************************************************************
	
	/** Clone method.*/
	@SuppressWarnings("unchecked")
	public Object clone() {
		try {
			AddQuadMouseCommand cmd = (AddQuadMouseCommand)super.clone();
			cmd.q = (GQuadCurve)q.clone();
			cmd.newCtrlPoints = (ArrayList<GPoint>) newCtrlPoints.clone();
			cmd.newPoints = (ArrayList<GPoint>) newPoints.clone();
			return cmd;
		}catch (CloneNotSupportedException e) {
			throw new Error("Clonning ERROR - This should never happen!");
		}
	}
	
//*****************************************************************************
	
	/** Returns the initial point of the curve being created.<br>
	* It's used to allow the use of both methods of inputing data (mouse and keyboard).
	* @return The initial point of the curve being created.
	*/
	public GPoint getInitialPoint() {
		return ini;
	}
	
//*****************************************************************************
	
	/** Sets the initial point of the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	* @param a The initial point of the curve being created.
	*/
	public void setInitialPoint(GPoint a) {
		ini = a;
	}
	
//*****************************************************************************
	
	/** Sets the final point of the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@param a The final point of the curve being created.
	*/
	public void setFinalPoint(GPoint a) {
		fin = a;
	}
	
//*****************************************************************************
	
	/** Returns the final point of the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@return The final point of the curve being created.
	*/
	public GPoint getFinalPoint() {
		return fin;
	}
	
//*****************************************************************************
	
	/** Sets the control point of the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@param a The control point of the curve being created.
	*/
	public void setControlPoint(GPoint a) {
		ctrl = a;
	}
	
//*****************************************************************************
	
	/** Returns the control point of the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@return The control point of the curve being created.
	*/
	public GPoint getControlPoint() {
		return ctrl;
	}
	
//*****************************************************************************
	
	/** Sets the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@param a The curve being created.
	*/
	public void setCurve(GQuadCurve a) {
		q = a;
	}
	
//*****************************************************************************
	
	/** Returns the curve being created.<br>
	* It's used to avoid errors when mixing both methods of inputing data (mouse and keyboard).
	*@return The curve being created.
	*/
	public GQuadCurve getCurve() {
		return q;
	}
//*****************************************************************************
	
	/** Sets the value of Clicks.
	*@param a The value of Clicks to be set.
	*/
	public void setClicks(int a) {
		clicks = a;
	}
	
//*****************************************************************************
	
	/** Returns the value of Clicks.
	*@return The value of Clicks.
	*/
	public int getClicks() {
		return clicks;
	}
	
//*****************************************************************************
	
	/** Adds a GPoint to the newPoints ArrayList.
	*@param a The GPoint to be added.
	*/
	public void addNewPoint(GPoint a) {
		newPoints.add(a);
	}
	
//*****************************************************************************
	
	/** Clears the newPoints ArrayList.*/
	public void clearNewPoints() {
		newPoints.clear();
	}
	
//*****************************************************************************
	
	/** Adds a GPoint to the newCtrlPoints ArrayList.
	*@param a The GPoint to be added.
	*/
	public void addNewCtrlPoint(GPoint a) {
		newCtrlPoints.add(a);
	}
	
//*****************************************************************************
	
	/** Clears the newCtrlPoints ArrayList.*/
	public void clearNewCtrlPoints() {
		newCtrlPoints.clear();
	}
	
//*****************************************************************************
}
